package com.ds.infrastructure.hyperspace.console.exceptions;

import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLockException;
import com.ds.infrastructure.hyperspace.console.enums.JsonResultCodeEnum;
import com.ds.infrastructure.hyperspace.console.model.response.result.JsonResult;
import com.ds.infrastructure.hyperspace.console.model.response.result.JsonResultError;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;

/**
 * @author  Weishaoying
 * @date 2019/7/8 下午4:23
 */
@ControllerAdvice
@Slf4j
public class BaseExceptionHandler {
    /**
     * 服务器内部已知异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(HyperspaceException.class)
    @ResponseBody
    JsonResult handlerHyperspaceException(HyperspaceException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INNER_KNOW_ERROR.code, e.getMessage());
    }

    /**
     * 方法参数验证失败
     *
     * @param e
     * @return
     */
    @ExceptionHandler({ArgumentValidException.class})
    @ResponseBody
    JsonResult argumentValidException(ArgumentValidException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, e.getMessage());
    }

    /**
     * 参数无效，如JSON请求参数违反约束
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    JsonResult handlerHyperspaceException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldError().getField() + e.getBindingResult().getFieldError().getDefaultMessage();
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, message);
    }

    /**
     * 参数缺失
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseBody
    JsonResult handlerHyperspaceException(MissingServletRequestParameterException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, e.getMessage());
    }

    /**
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    JsonResult handlerHyperspaceException(HttpMessageNotReadableException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, e.getMessage());
    }

    /**
     * 参数类型不匹配
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    JsonResult handlerHyperspaceException(MethodArgumentTypeMismatchException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, e.getMessage());
    }

    /**
     * 服务器内部未知异常-需要特殊处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler()
    @ResponseBody
    JsonResult handlerException(Exception e) {
        log.error("系统异常:", e);
        String error = e.getMessage() == null ? e.toString() : e.getMessage();
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INNER_UNKNOW_ERROR.code, error);
    }

    /**
     * 方法锁异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodLockException.class)
    @ResponseBody
    JsonResult handlerMethodLockException(MethodLockException e) {
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INNER_KNOW_ERROR.code, e.getMessage());
    }

    /**
     * 参数格式异常验证 ConstraintViolationException
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    JsonResult handlerConstraintViolationException(Exception e) {
        String error = e.getMessage() == null ? e.toString() : e.getMessage();
        return JsonResultError.build(JsonResultCodeEnum.ERROR.INVALID_REQUEST_PARAMETERS.code, error);
    }

    /**
     * 认证错误：
     *
     * @param e
     * @return
     */
    @ExceptionHandler(UnauthenticatedException.class)
    @ResponseBody
    JsonResult handlerUnauthenticatedException(Exception e, HttpServletResponse httpResponse) {
        return getUnauthorizedErrorJsonResult(e, HttpStatus.UNAUTHORIZED, httpResponse);
    }

    /**
     * 授权错误:当用户被认证后，但用户没有被授权在特定资源上执行操作
     *
     * @param e
     * @return
     */
    @ExceptionHandler(UnauthorizedException.class)
    @ResponseBody
    JsonResult handlerUnauthorizedException(Exception e, HttpServletResponse httpResponse) {
        return getUnauthorizedErrorJsonResult(e, HttpStatus.FORBIDDEN, httpResponse);
    }

    private JsonResult getUnauthorizedErrorJsonResult(Exception e, HttpStatus unauthorized, HttpServletResponse httpResponse) {
        httpResponse.setStatus(unauthorized.value());
        String error = e.getMessage() == null ? e.toString() : e.getMessage();
        return JsonResultError.build(unauthorized.value(), error);
    }

    @ExceptionHandler(AuthorizationException.class)
    @ResponseBody
    JsonResult handlerAuthorizationException(Exception e, HttpServletResponse httpResponse) {

        return getUnauthorizedErrorJsonResult(e, HttpStatus.FORBIDDEN, httpResponse);
    }

}
